package cn.tqfeiyang.springplus.generator.jdbc;

import cn.tqfeiyang.springplus.generator.config.GeneratorConfig;
import cn.tqfeiyang.springplus.generator.config.TableFill;
import cn.tqfeiyang.springplus.generator.name.NameConverter;
import cn.tqfeiyang.springplus.generator.type.DbColumnType;
import cn.tqfeiyang.springplus.generator.type.TypeRegistry;
import cn.tqfeiyang.springplus.generator.name.NameFormat;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.Getter;
import org.apache.ibatis.type.JdbcType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据库查询类
 */
public class DatabaseQuery {

    private static final Logger logger = LoggerFactory.getLogger(DatabaseQuery.class);

    @Getter
    private final GeneratorConfig generatorConfig;

    @Getter
    private Connection connection;

    @Getter
    private DatabaseMetaData databaseMetaData;

    @Getter
    //TODO 暂时只支持一种
    private String catalog;

    @Getter
    //TODO 暂时只支持一种
    private String schema;

    @Getter
    protected TypeRegistry typeRegistry;

    public DatabaseQuery(GeneratorConfig generatorConfig) {
        this.generatorConfig = generatorConfig;
        this.typeRegistry = new TypeRegistry(generatorConfig);
    }

    /**
     * 获取表信息列表
     *
     * @return 表信息
     */
    public List<TableInfo> queryTables() {
        try {
            openConnection();

            //所有的表信息
            List<TableInfo> tableList = new ArrayList<>();

            //需要反向生成或排除的表信息
            List<TableInfo> includeTableList = new ArrayList<>();
            List<TableInfo> excludeTableList = new ArrayList<>();

            List<TableInfo> tables = getTables();
            generatorConfig.setAllTables(tables);

            //所有表的字段都需要处理
            tables.forEach(this::convertFields);

            //针对交叉表，创建交叉数据
            tables.forEach(tableInfo -> {
                if (tableInfo.getTableType().equalsIgnoreCase("CROSS")) {
                    queryCrossInfo(tableInfo);
                }
            });

            tables.forEach(this::queryMultiToOneJoins);
            tables.forEach(this::queryOneToMultiJoins);
            tables.forEach(this::queryMultiToMultiJoins);

            tables.forEach(tableInfo -> {
                if (matchIncludeTable(tableInfo.getName())) {
                    includeTableList.add(tableInfo);
                } else if (matchExcludeTable(tableInfo.getName())) {
                    excludeTableList.add(tableInfo);
                }
                tableList.add(tableInfo);
            });

            filter(tableList, includeTableList, excludeTableList);

            return tableList;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 数据库操作完成,释放连接对象
            closeConnection();
        }
    }

    protected List<TableInfo> getTables() {
        // 是否跳过视图
        boolean skipView = generatorConfig.isSkipView();
        // 获表过滤
        String tableNamePattern = generatorConfig.getTableNamePattern();
        // 表类型
        String[] types = skipView ? new String[]{"TABLE"} : new String[]{"TABLE", "VIEW"};

        List<TableInfo> tables = new ArrayList<>();

        try (ResultSet resultSet = databaseMetaData.getTables(catalog, schema, tableNamePattern, types)) {
            while (resultSet.next()) {
                TableInfo tableInfo = new TableInfo();
                tableInfo.setGeneratorConfig(generatorConfig);
                tableInfo.setName(resultSet.getString("TABLE_NAME"));
                tableInfo.setTableType(resultSet.getString("TABLE_TYPE"));
                tableInfo.setSchema(schema);
                tableInfo.setCatalog(catalog);

                // 注释
                String comment = formatRemarks(resultSet.getString("REMARKS"));
                if (StringUtils.endsWith(comment, "信息")) {
                    comment = org.apache.commons.lang3.StringUtils.removeEnd(comment, "信息");
                }
                tableInfo.setComment(comment);

                // 实体名
//                String entityName = generatorConfig.getNameConverter().convert(tableInfo, NameFormat.EntityName);
//                tableInfo.setEntityName(entityName);

                // 从数据库读取配置
                updateTableFromSQL(tableInfo);

                tables.add(tableInfo);
            }
        } catch (SQLException e) {
            throw new RuntimeException("读取数据库表信息出现错误", e);
        }
        return tables;
    }

    protected void filter(List<TableInfo> tableList, List<TableInfo> includeTableList, List<TableInfo> excludeTableList) {
        boolean isInclude = !generatorConfig.getIncludeTables().isEmpty();
        boolean isExclude = !generatorConfig.getExcludeTables().isEmpty();
        if (isExclude || isInclude) {
            Map<String, String> notExistTables = new HashSet<>(isExclude ? generatorConfig.getExcludeTables() : generatorConfig.getIncludeTables())
                    .stream()
                    .collect(Collectors.toMap(String::toLowerCase, s -> s, (o, n) -> n));
            // 将已经存在的表移除，获取配置中数据库不存在的表
            for (TableInfo tabInfo : tableList) {
                if (notExistTables.isEmpty()) {
                    break;
                }
                //解决可能大小写不敏感的情况导致无法移除掉
                notExistTables.remove(tabInfo.getName().toLowerCase());
            }
            if (!notExistTables.isEmpty()) {
                logger.warn("表[{}]在数据库中不存在！！！", String.join(StringPool.COMMA, notExistTables.values()));
            }
            // 需要反向生成的表信息
            if (isExclude) {
                tableList.removeAll(excludeTableList);
            } else {
                tableList.clear();
                tableList.addAll(includeTableList);
            }
        }
    }

    protected void convertFields(TableInfo tableInfo) {
        Set<String> primaryKeys = new HashSet<>();
        try (ResultSet resultSet = databaseMetaData.getPrimaryKeys(catalog, schema, tableInfo.getName())) {
            while (resultSet.next()) {
                String columnName = resultSet.getString("COLUMN_NAME");
                primaryKeys.add(columnName);
            }
            if (primaryKeys.size() > 1) {
                logger.warn("当前表 {} 存在多主键情况！", tableInfo.getName());
            }
        } catch (SQLException e) {
            throw new RuntimeException("读取表主键信息:" + tableInfo.getName() + "错误:", e);
        }

        try (ResultSet resultSet = databaseMetaData.getColumns(catalog, schema, tableInfo.getName(), "%")) {
            while (resultSet.next()) {
                String fieldName = resultSet.getString("COLUMN_NAME");
                FieldInfo fieldInfo = new FieldInfo();
                fieldInfo.setGeneratorConfig(generatorConfig);
                fieldInfo.setTable(tableInfo);
                fieldInfo.setTable(tableInfo);
                fieldInfo.setName(fieldName);
                fieldInfo.setRemarks(formatRemarks(resultSet.getString("REMARKS")));
                fieldInfo.setComment(fieldInfo.getExtra(null));
                //数据库原始字段名，可能存在JAVA关键字等特殊情况
                fieldInfo.setColumnName(fieldName);
                fieldInfo.setPrimaryKey(primaryKeys.contains(fieldInfo.getName()));
                fieldInfo.setSqlType(resultSet.getString("TYPE_NAME"));
                fieldInfo.setLength(resultSet.getInt("COLUMN_SIZE"));
                fieldInfo.setScale(resultSet.getInt("DECIMAL_DIGITS"));
                fieldInfo.setNullable(resultSet.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
                fieldInfo.setAutoIncrement("YES".equals(resultSet.getString("IS_AUTOINCREMENT")));
                fieldInfo.setDefaultValue(resultSet.getString("COLUMN_DEF"));

                // 处理主键
                if (fieldInfo.isPrimaryKey()) {
//                    tableInfo.setHavePrimaryKey(true);
//                    tableInfo.setKeyField(fieldInfo);
                    if (fieldInfo.isAutoIncrement() && generatorConfig.getEntityIdType() != null) {
                        logger.warn("当前表 [{}] 的主键为自增主键，会导致全局主键的ID类型设置失效!", tableInfo.getName());
                    }
                }

                // 排序字段
                if (fieldInfo.getColumnName().equalsIgnoreCase("sort")) {
//                    tableInfo.setSortField(fieldInfo);
                }

                // JDBC数据类型
                int dataType = resultSet.getInt("DATA_TYPE");
                JdbcType jdbcType = JdbcType.forCode(dataType);
                if (jdbcType == null) {
                    // 不标准的类型,统一转为OTHER
                    jdbcType = JdbcType.OTHER;
                }
                fieldInfo.setJdbcType(jdbcType);

                // 列类型，DATE("Date", "java.util.Date")
                DbColumnType columnType = typeRegistry.getColumnType(fieldInfo);
                fieldInfo.setColumnType(columnType);
//                if (StringUtils.isNotBlank(columnType.getPkg()) && !tableInfo.getImportPackages().contains(columnType.getPkg())) {
//                    tableInfo.getImportPackages().add(columnType.getPkg());
//                }

                // 变量名, 如果是is开头可能需要去掉
                //String propertyName = generatorConfig.getNameConverter().convert(fieldInfo, NameFormat.VariableName);
                //fieldInfo.setPropertyName(propertyName);
                //fieldInfo.setPropertyType(columnType.getType());

                // 特殊字段标识
                fieldInfo.setVersionFlag(fieldName.equalsIgnoreCase(generatorConfig.getVersionColumnName()));
                fieldInfo.setLogicDeleteFlag(fieldName.equalsIgnoreCase(generatorConfig.getLogicDeleteColumnName()));
                fieldInfo.setCreateTimeFlag(fieldName.equalsIgnoreCase(generatorConfig.getCreateTimeColumnName()));
                fieldInfo.setCreateUserFlag(fieldName.equalsIgnoreCase(generatorConfig.getCreateUserColumnName()));
                fieldInfo.setUpdateTimeFlag(fieldName.equalsIgnoreCase(generatorConfig.getUpdateUserColumnName()));
                fieldInfo.setUpdateUserFlag(fieldName.equalsIgnoreCase(generatorConfig.getUpdateUserColumnName()));

                // 字段填充
                fieldInfo.setFillMode(findTableFill(fieldInfo.getColumnName()));

                // 从数据库读取配置
                updateFieldFromSQL(fieldInfo);

                if (matchIgnoreColumns(fieldInfo.getColumnName())) {
                    // 忽略字段不在处理
                } else if (matchSuperEntityColumns(fieldInfo.getColumnName())) {
                    tableInfo.getCommonFields().add(fieldInfo);
                } else {
                    tableInfo.getFields().add(fieldInfo);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException("读取表字段信息:" + tableInfo.getName() + "错误:", e);
        }
    }

    protected boolean matchIncludeTable(String tableName) {
        return generatorConfig.getIncludeTables().stream().anyMatch(t -> t.equalsIgnoreCase(tableName));
    }

    protected boolean matchExcludeTable(String tableName) {
        return generatorConfig.getExcludeTables().stream().anyMatch(t -> t.equalsIgnoreCase(tableName));
    }

    protected boolean matchSuperEntityColumns(String columnName) {
        return generatorConfig.getSuperEntityColumns().stream().anyMatch(e -> e.equalsIgnoreCase(columnName));
    }

    protected boolean matchIgnoreColumns(String columnName) {
        return generatorConfig.getIgnoreColumns().stream().anyMatch(e -> e.equalsIgnoreCase(columnName));
    }

    protected String findTableFill(String columnName) {
        TableFill tableFill = generatorConfig.getTableFills().stream()
                .filter(e -> e.getColumnName().equalsIgnoreCase(columnName))
                .findFirst()
                .orElse(null);
        return tableFill != null ? tableFill.getFillMode().name() : null;
    }

    private void openConnection() {
        try {
            synchronized (this) {
                Properties properties = new Properties();
                generatorConfig.getConnectionProperties().forEach(properties::setProperty);
                properties.put("user", generatorConfig.getJdbcUsername());
                properties.put("password", generatorConfig.getJdbcPassword());
                // 使用元数据查询方式时，有些数据库需要增加属性才能读取注释
                processProperties(properties);
                this.connection = DriverManager.getConnection(generatorConfig.getJdbcUrl(), properties);
                this.databaseMetaData = connection.getMetaData();
                this.catalog = connection.getCatalog();
                this.schema = connection.getSchema();

                connection.prepareStatement("insert into sys_generator_table(table_name, table_comment) " +
                                "select t.TABLE_NAME, t.TABLE_COMMENT " +
                                "from information_schema.TABLES t " +
                                "where TABLE_SCHEMA = DATABASE() " +
                                "and not exists (select 1 from sys_generator_table where table_name = t.TABLE_NAME)")
                        .execute();

                connection.prepareStatement("insert into sys_generator_field(table_name, field_name, field_comment) " +
                        "select c.TABLE_NAME, c.COLUMN_NAME, c.COLUMN_COMMENT " +
                        "from information_schema.COLUMNS c " +
                        "where TABLE_SCHEMA = DATABASE() " +
                        "and c.COLUMN_NAME not in ('version', 'deleted', 'create_time', 'create_user', 'update_time', 'update_user') " +
                        "and not exists (select 1 from sys_generator_field where table_name = c.TABLE_NAME and field_name = c.COLUMN_NAME)")
                        .execute();

            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private void processProperties(Properties properties) {
        switch (getDbType()) {
            case MYSQL:
                properties.put("remarks", "true");
                properties.put("useInformationSchema", "true");
                break;
            case ORACLE:
                properties.put("remarks", "true");
                properties.put("remarksReporting", "true");
                break;
        }
    }

    private void closeConnection() {
        Optional.ofNullable(connection).ifPresent((con) -> {
            try {
                con.close();
            } catch (SQLException sqlException) {
                sqlException.printStackTrace();
            }
        });
    }

    protected String formatRemarks(String remarks) {
        return StringUtils.isBlank(remarks) ? StringPool.EMPTY : remarks.replaceAll("\r\n", "\t");
    }

//    /**
//     * 解析注释
//     *
//     * 注释格式：
//     * 优先级
//     * 优先级#enum=cn.cn.tqfeiyang.smartadmin.office.constant.PriorityEnum
//     *
//     * @param comment
//     * @param type
//     * @return 注释
//     */
//    protected String parseComment(String comment, String type) {
//        if (StringUtils.isBlank(comment)) {
//            return null;
//        }
//
//        // 如果没有指定type，则返回字段说明，否则返回对应的参数值
//        String[] items = org.apache.commons.lang3.StringUtils.split(comment, "#");
//        if (StringUtils.isBlank(type)) {
//            return items[0].trim();
//        } else {
//            for (String item : items) {
//                String[] tokens = org.apache.commons.lang3.StringUtils.split(item, "=", 2);
//                if (tokens.length == 2 && type.equalsIgnoreCase(tokens[0])) {
//                    return tokens[1];
//                }
//            }
//            return null;
//        }
//    }

    protected String getDefaultSchema() {
        DbType dbType = getDbType();
        String schema = null;
        if (DbType.POSTGRE_SQL == dbType) {
            //pg 默认 schema=public
            schema = "public";
        } else if (DbType.KINGBASE_ES == dbType) {
            //kingbase 默认 schema=PUBLIC
            schema = "PUBLIC";
        } else if (DbType.DB2 == dbType) {
            //db2 默认 schema=current schema
            schema = "current schema";
        } else if (DbType.ORACLE == dbType) {
            //oracle 默认 schema=username
            schema = generatorConfig.getJdbcUsername().toUpperCase();
        }
        return schema;
    }

    protected DbType getDbType() {
        String url = generatorConfig.getJdbcUrl();
        if (url.contains(":mysql:") || url.contains(":cobar:")) {
            return DbType.MYSQL;
        } else if (url.contains(":oracle:")) {
            return DbType.ORACLE;
        } else if (url.contains(":postgresql:")) {
            return DbType.POSTGRE_SQL;
        } else if (url.contains(":sqlserver:")) {
            return DbType.SQL_SERVER;
        } else if (url.contains(":db2:")) {
            return DbType.DB2;
        } else if (url.contains(":mariadb:")) {
            return DbType.MARIADB;
        } else if (url.contains(":sqlite:")) {
            return DbType.SQLITE;
        } else if (url.contains(":h2:")) {
            return DbType.H2;
        } else if (url.contains(":lealone:")) {
            return DbType.LEALONE;
        } else if (url.contains(":kingbase:") || url.contains(":kingbase8:")) {
            return DbType.KINGBASE_ES;
        } else if (url.contains(":dm:")) {
            return DbType.DM;
        } else if (url.contains(":zenith:")) {
            return DbType.GAUSS;
        } else if (url.contains(":oscar:")) {
            return DbType.OSCAR;
        } else if (url.contains(":firebird:")) {
            return DbType.FIREBIRD;
        } else if (url.contains(":xugu:")) {
            return DbType.XU_GU;
        } else if (url.contains(":clickhouse:")) {
            return DbType.CLICK_HOUSE;
        } else if (url.contains(":sybase:")) {
            return DbType.SYBASE;
        } else {
            return DbType.OTHER;
        }
    }

    private void updateTableFromSQL(TableInfo tableInfo) throws SQLException {
        String sql = "SELECT * FROM sys_generator_table WHERE table_name = ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, tableInfo.getName());
        ResultSet resultSet = statement.executeQuery();
        if (resultSet.next()) {
            String tableComment = resultSet.getString("table_comment");
            if (StringUtils.isNotBlank(tableComment)) {
                tableInfo.setComment(tableComment);
            }

            String tableType = resultSet.getString("table_type");
            if (StringUtils.isNotBlank(tableType)) {
                tableInfo.setTableType(tableType);
            }

            String moduleName = resultSet.getString("module_name");
            if (StringUtils.isNotBlank(moduleName)) {
                tableInfo.setModuleName(moduleName);
            }

            String domainName = resultSet.getString("domain_name");
            if (StringUtils.isNotBlank(domainName)) {
                tableInfo.setDomainName(domainName);
            }

            String apifoxFolder = resultSet.getString("apifox_folder");
            if (StringUtils.isNotBlank(apifoxFolder)) {
                tableInfo.setApifoxFolder(apifoxFolder);
            }

            tableInfo.setSupportMapper(resultSet.getInt("support_mapper") > 0);
            tableInfo.setSupportService(resultSet.getInt("support_service") > 0);
            tableInfo.setSupportController(resultSet.getInt("support_controller") > 0);
            tableInfo.setSupportCache(resultSet.getInt("support_cache") > 0);
        }
        resultSet.close();
        statement.close();
    }

    private void queryMultiToOneJoins(TableInfo tableInfo) {
        try {
            String sql = "SELECT field_name, join_table_name FROM sys_generator_field WHERE table_name = ? and join_table_name <> ''";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, tableInfo.getName());
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                String fieldName = resultSet.getString("field_name");
                FieldInfo fieldInfo = findFieldInfo(tableInfo, fieldName);
                if (fieldInfo != null) {
                    String joinTableName = resultSet.getString("join_table_name");
                    TableInfo joinTableInfo = findTableInfo(joinTableName);
                    if (joinTableInfo != null) {
                        JoinInfo.ManyToOneJoin manyToOneJoin = new JoinInfo.ManyToOneJoin();
                        manyToOneJoin.setGeneratorConfig(generatorConfig);
                        manyToOneJoin.setThisTable(tableInfo);
                        manyToOneJoin.setThisField(fieldInfo);
                        manyToOneJoin.setJoinTable(joinTableInfo);
                        manyToOneJoin.setJoinField(joinTableInfo.getKeyField());
                        manyToOneJoin.setComment(fieldInfo.getComment().toLowerCase().replace("id", ""));
                        fieldInfo.setManyToOneJoin(manyToOneJoin);
                    }
                }
            }
            resultSet.close();
            statement.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private void queryOneToMultiJoins(TableInfo tableInfo) {
        try {
            String sql = "SELECT DISTINCT table_name, field_name FROM sys_generator_field WHERE join_table_name = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, tableInfo.getName());
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                String joinTableName = resultSet.getString("table_name");
                TableInfo joinTableInfo = findTableInfo(joinTableName);
                String joinFieldName = resultSet.getString("field_name");
                FieldInfo joinFieldInfo = findFieldInfo(joinTableInfo, joinFieldName);
                if (joinTableInfo != null && joinFieldInfo != null) {
                    JoinInfo.OneToManyJoin oneToManyJoin = new JoinInfo.OneToManyJoin();
                    oneToManyJoin.setGeneratorConfig(generatorConfig);
                    oneToManyJoin.setThisTable(tableInfo);
                    oneToManyJoin.setThisField(tableInfo.getKeyField());
                    oneToManyJoin.setJoinTable(joinTableInfo);
                    oneToManyJoin.setJoinField(joinFieldInfo);
                    oneToManyJoin.setComment(joinTableInfo.getComment());
                    tableInfo.getOneToManyJoins().add(oneToManyJoin);
                }
            }
            resultSet.close();
            statement.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private void queryMultiToMultiJoins(TableInfo tableInfo) {
        try {
            String sql = "SELECT * FROM sys_generator_m2m WHERE left_table_name = ? OR right_table_name = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, tableInfo.getName());
            statement.setString(2, tableInfo.getName());
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                String crossTableName = resultSet.getString("cross_table_name");
                TableInfo crossTableInfo = findTableInfo(crossTableName);
                if (crossTableInfo != null && crossTableInfo.getCrossInfo() != null) {
                    String leftTableName = resultSet.getString("left_table_name");
                    TableInfo leftTableInfo = findTableInfo(leftTableName);
                    String rightTableName = resultSet.getString("right_table_name");
                    TableInfo rightTableInfo = findTableInfo(rightTableName);
                    if (leftTableInfo != null && rightTableInfo != null) {
                        String leftFieldName = resultSet.getString("left_field_name");
                        FieldInfo leftFieldInfo = findFieldInfo(crossTableInfo, leftFieldName);
                        String rightFieldName = resultSet.getString("right_field_name");
                        FieldInfo rightFieldInfo = findFieldInfo(crossTableInfo, rightFieldName);
                        if (leftFieldInfo != null && rightFieldInfo != null) {
                            JoinInfo.ManyToManyJoin manyToManyJoin = new JoinInfo.ManyToManyJoin();
                            manyToManyJoin.setGeneratorConfig(generatorConfig);
                            if (tableInfo.getName().equalsIgnoreCase(leftTableName)) {
                                manyToManyJoin.setThisTable(leftTableInfo);
                                manyToManyJoin.setThisField(leftTableInfo.getKeyField());
                                manyToManyJoin.setJoinTable(rightTableInfo);
                                manyToManyJoin.setJoinField(rightTableInfo.getKeyField());
                                manyToManyJoin.setCrossTable(crossTableInfo);
                                manyToManyJoin.setCrossThisField(leftFieldInfo);
                                manyToManyJoin.setCrossJoinField(rightFieldInfo);
                                manyToManyJoin.setComment(rightTableInfo.getComment());
                                crossTableInfo.getCrossInfo().setLeftJoin(manyToManyJoin);
                            } else {
                                manyToManyJoin.setThisTable(rightTableInfo);
                                manyToManyJoin.setThisField(rightTableInfo.getKeyField());
                                manyToManyJoin.setJoinTable(leftTableInfo);
                                manyToManyJoin.setJoinField(leftTableInfo.getKeyField());
                                manyToManyJoin.setCrossTable(crossTableInfo);
                                manyToManyJoin.setCrossThisField(rightFieldInfo);
                                manyToManyJoin.setCrossJoinField(leftFieldInfo);
                                manyToManyJoin.setComment(leftTableInfo.getComment());
                                crossTableInfo.getCrossInfo().setRightJoin(manyToManyJoin);
                            }
                            tableInfo.getManyToManyJoins().add(manyToManyJoin);
                        }
                    }
                }
            }
            resultSet.close();
            statement.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private void queryCrossInfo(TableInfo tableInfo) {
        try {
            String sql = "SELECT * FROM sys_generator_m2m WHERE cross_table_name = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, tableInfo.getName());
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                String crossTableName = resultSet.getString("cross_table_name");
                TableInfo crossTableInfo = findTableInfo(crossTableName);
                String leftTableName = resultSet.getString("left_table_name");
                TableInfo leftTableInfo = findTableInfo(leftTableName);
                String rightTableName = resultSet.getString("right_table_name");
                TableInfo rightTableInfo = findTableInfo(rightTableName);
                if (crossTableInfo != null && leftTableInfo != null && rightTableInfo != null) {
                    String leftFieldName = resultSet.getString("left_field_name");
                    FieldInfo leftFieldInfo = findFieldInfo(crossTableInfo, leftFieldName);
                    String rightFieldName = resultSet.getString("right_field_name");
                    FieldInfo rightFieldInfo = findFieldInfo(crossTableInfo, rightFieldName);
                    CrossInfo crossInfo = new CrossInfo();
                    crossInfo.setGeneratorConfig(generatorConfig);
                    crossInfo.setCrossTable(crossTableInfo);
                    crossInfo.setLeftTable(leftTableInfo);
                    crossInfo.setLeftField(leftFieldInfo);
                    crossInfo.setRightTable(rightTableInfo);
                    crossInfo.setRightField(rightFieldInfo);
                    tableInfo.setCrossInfo(crossInfo);
                }
            }
            resultSet.close();
            statement.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private TableInfo findTableInfo(String tableName) {
        return generatorConfig.getAllTables().stream()
                .filter(tableInfo -> tableInfo.getName().equalsIgnoreCase(tableName))
                .findFirst()
                .orElse(null);
    }

    private FieldInfo findFieldInfo(String tableName, String fieldName) {
        TableInfo tableInfo = findTableInfo(tableName);
        return tableInfo != null ? findFieldInfo(tableInfo, fieldName) : null;
    }

    private FieldInfo findFieldInfo(TableInfo tableInfo, String fieldName) {
        return tableInfo.getFields().stream()
                .filter(fieldInfo -> fieldInfo.getName().equalsIgnoreCase(fieldName))
                .findFirst()
                .orElse(null);
    }

    private void updateFieldFromSQL(FieldInfo fieldInfo) throws SQLException {
        String sql = "SELECT * FROM sys_generator_field WHERE table_name = ? AND field_name = ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, fieldInfo.getTable().getName());
        statement.setString(2, fieldInfo.getName());
        ResultSet resultSet = statement.executeQuery();
        if (resultSet.next()) {
            String fieldComment = resultSet.getString("field_comment");
            if (StringUtils.isNotBlank(fieldComment)) {
                fieldInfo.setComment(fieldComment);
            }

//            fieldInfo.setJoinTableName(resultSet.getString("join_table_name"));
            fieldInfo.setSupportQueryRequest(resultSet.getInt("support_query_request") > 0);
            fieldInfo.setSupportCreateRequest(resultSet.getInt("support_create_request") > 0);
            fieldInfo.setSupportUpdateRequest(resultSet.getInt("support_update_request") > 0);
            fieldInfo.setSupportQueryResponse(resultSet.getInt("support_query_response") > 0);
            fieldInfo.setSupportDetailResponse(resultSet.getInt("support_detail_response") > 0);

            // 特殊处理
            if (fieldInfo.isAutoIncrement() || fieldInfo.isLogicDeleteFlag() || fieldInfo.isVersionFlag()
                || fieldInfo.isCreateTimeFlag() || fieldInfo.isCreateUserFlag()
                || fieldInfo.isUpdateTimeFlag() || fieldInfo.isUpdateUserFlag()) {
                fieldInfo.setSupportCreateRequest(false);
                fieldInfo.setSupportUpdateRequest(false);
                fieldInfo.setSupportQueryRequest(false);
                fieldInfo.setSupportQueryResponse(true);
                fieldInfo.setSupportDetailResponse(true);
            }

            fieldInfo.setRequired(resultSet.getInt("is_required") > 0);
            fieldInfo.setUnique(resultSet.getInt("is_unique") > 0);

            if (resultSet.getInt("is_unique") > 0) {
                NameConverter nameConverter = generatorConfig.getNameConverter();
                String methodName = nameConverter.convert(fieldInfo.getTable(), NameFormat.MapperVariable)
                        + "." + nameConverter.convert(fieldInfo, NameFormat.ExistsMethod);
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "",
                        methodName,
                        "检查%s是否重复？",
                        "%s重复",
                        null,
                        true));
            }
            if (resultSet.getInt("is_chinese_name") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsChineseName",
                        "Validator.isChineseName",
                        "检查%s是否为中文姓名（2-60位，只能是中文和 ·）？",
                        "%s不是正确的中文姓名",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_uuid") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsUUID",
                        "!Validator.isUUID",
                        "检查%s是否为UUID？",
                        "%s不是正确的UUID",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_url") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsUrl",
                        "!Validator.isUrl",
                        "检查%s是否为URL？",
                        "%s不是正确的URL",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_email") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsEmail",
                        "!Validator.isEmail",
                        "检查%s是否为邮箱地址？",
                        "%s不是正确的邮箱地址",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_mobile") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsMobile",
                        "!Validator.isMobile",
                        "检查%s是否为手机号码（中国）？",
                        "%s不是正确的手机号码",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_zip_code") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsZipCode",
                        "!Validator.isZipCode",
                        "检查%s是否为邮政编码（中国）？",
                        "%s不是正确的邮政编码",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_citizen_id") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsCitizenId",
                        "!Validator.isCitizenId",
                        "检查%s是否为身份证号码（支持18位、15位和港澳台的10位）？",
                        "%s不是正确的身份证号码",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_ipv4") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsIpv4",
                        "!Validator.isIpv4",
                        "检查%s是否为IPV4地址？",
                        "%s不是正确的IPV4地址",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_ipv6") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsIpv6",
                        "!Validator.isIpv6",
                        "检查%s是否为IPV6地址？",
                        "%s不是正确的IPV6地址",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_mac") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsMac",
                        "!Validator.isMac",
                        "检查%s是否为MAC地址？",
                        "%s不是正确的MAC地址",
                        "cn.hutool.core.lang.Validator"));
            }
            if (resultSet.getInt("is_plate_number") > 0) {
                fieldInfo.getValidators().add(new ValidatorInfo(
                        generatorConfig,
                        fieldInfo,
                        "IsPlateNumber",
                        "!Validator.isPlateNumber",
                        "检查%s是否为中国车牌号？",
                        "%s不是正确的中国车牌号",
                        "cn.hutool.core.lang.Validator"));
            }
        }
        resultSet.close();
        statement.close();
    }
}
